package parse

import (
	"api_online/config"
	"api_online/data"
	"api_online/helpers"
	"bufio"
	"os"
	"regexp"
	"strings"
)

const tagFileDesc = "@fileDesc"
const tagApi = "@api"
const tagApiDesc = "@desc"
const tagApiAuthor = "@author"
const tagApiTime = "@time"
const tagApiMethod = "@method"
const tagApiParam = "@param"
const tagIsRequired = "*"
const tagAnnotation = "*"



func InitSyntaxTree() {
	// 目录 -> 文件
	path := config.Config.GetPath()

	// 根据控制器硬盘目录遍历文件夹,得到文件数组
	fileArr := helpers.GetFileList(path, "")

	// 文件 -> 接口 -> 详情
	// 循环遍历文件,获取文件信息
	for _, file := range fileArr {
		syntaxFile, SyntaxApiList := Parse(path, file)

		data.Cache.SetSyntaxFile(syntaxFile, SyntaxApiList)
	}
}

func Parse(filePath string, fileName string) (data.SyntaxFile, []data.SyntaxApi) {

	// 初始化变量,用于控制遍历时候的行为
	parseIng := false                      // 解析中,用于区分不同接口
	var apiList []data.SyntaxApi           // 接口列表
	var apiline data.SyntaxApi             // 单个接口详情
	var apiParamList []data.SyntaxApiParam // 接口参数列表
	var fileNameMain string

	fileNameMain = helpers.Lcfirst(strings.TrimSuffix(fileName, config.Config.GetSuffix())) // 文件名,不包含扩展名

	// 文件语法树-文件名
	syntaxFile := data.SyntaxFile{
		FileName: fileNameMain,
	}

	f, err := os.Open(filePath + fileName)
	if err != nil {
		panic(err)
	}
	defer f.Close()
	rd := bufio.NewReader(f)

	for {
		// 读取一行数据
		line, _, err := rd.ReadLine()
		if err != nil {
			break
		}

		arr := getArrByLine(line)
		// 去掉空行
		if len(arr) == 0 {
			continue
		}

		tag := getTagByArr(arr)
		if tag == "" && !isStartCode(line) {
			continue
		}
		// 文件语法树-描述
		if tag == tagFileDesc {
			syntaxFile.Desc = getValByArr(arr)
			continue
		}

		// 具体接口开始
		if tag == tagApi {
			parseIng = true
			continue
		}

		if parseIng {

			if tag == tagApiDesc {
				apiline.Desc = getValByArr(arr)
				continue
			}
			if tag == tagApiAuthor {
				apiline.Author = getValByArr(arr)
				continue
			}
			if tag == tagApiTime {
				apiline.Time = getTimeByArr(arr)
				continue
			}
			if tag == tagApiMethod {
				apiline.Method = getValByArr(arr)
				continue
			}
			if tag == tagApiParam {
				apiParamList = append(apiParamList, getParamByArr(arr))
				continue
			}
		}

		if parseIng && isStartCode(line) {
			// 一个接口的结束
			apiName := getFunctionNameByArr(arr)
			apiline.Url = fileNameMain + "/" + apiName
			apiline.Param = apiParamList
			apiList = append(apiList, apiline)
			apiline = data.SyntaxApi{}
			apiParamList = []data.SyntaxApiParam{}
			parseIng = false
			continue
		}
	}
	return syntaxFile, apiList
}

func compressStr(str string) string {
	if str == "" {
		return ""
	}
	//匹配一个或多个空白符的正则表达式
	reg := regexp.MustCompile("\\s+")
	return reg.ReplaceAllString(str, "")
}

func getArrByLine(byte []byte) []string {
	line := string(byte)
	arr := strings.Fields(line)

	// 去掉空行
	if len(arr) <= 1 {
		return []string{}
	}
	return arr
}

func getTagByArr(arr []string) string {
	// 去掉非标记
	if !(arr[0] == tagAnnotation) || !strings.Contains(arr[1], "@") {
		return ""
	}

	if len(arr) > 1 {
		return arr[1]
	}
	return ""
}

func getValByArr(arr []string) string {
	if len(arr) >2 {
		return arr[2]
	}
	return ""
}

func getTimeByArr(arr []string) string {
	length := len(arr)
	lineTime := ""
	if length >= 3 {
		lineTime += arr[2]
	}
	if length >= 4 {
		lineTime += arr[3]
	}
	return lineTime
}

func getParamByArr(arr []string) data.SyntaxApiParam {
	// 必填
	isRequired := false
	if arr[3] == tagIsRequired {
		isRequired = true
	}

	// 默认值
	valDefault := ""
	if arr[3] != tagIsRequired {
		valDefault = arr[3]
	}

	// 字段含义
	name := ""
	if len(arr) >= 5 {
		name = arr[4]
	}

	return data.SyntaxApiParam{
		Key: arr[2],
		IsRequired: isRequired,
		Default: valDefault,
		Name: name,
	}
}

func isStartCode(byte []byte) bool {
	line := string(byte)
	return strings.Contains(line, "function")
}

func getFunctionNameByArr(arr []string) string {
	return strings.TrimSuffix(arr[2], "()")
}